#include "serialportctrl.h"
// 串口控制类
std::once_flag  SerialportCtrl::m_initFlag;
std::unique_ptr<SerialportCtrl> SerialportCtrl::m_pInstance = nullptr;
SerialportCtrl::SerialportCtrl(QObject* parent)
    :QObject(parent)
{
}

// 析构函数
SerialportCtrl::~SerialportCtrl()
{

}

// 静态函数
SerialportCtrl* SerialportCtrl::instance()
{
    std::call_once(m_initFlag, [&]() {m_pInstance = std::unique_ptr<SerialportCtrl>(new SerialportCtrl()); });
    return m_pInstance.get();
}

// 相应打开槽
void SerialportCtrl::initWork()
{
    SERIALPORTCONFIG_INSTANCE->getSerialPortInfo(m_vecSerialInfo);

    for (int i = 0; i < m_vecSerialInfo.size(); i++)
    {
        init_open_serial(m_vecSerialInfo[i]);
    }
}

// 初始打开串口
bool SerialportCtrl::init_open_serial(PSeriaPortInfo info)
{
    SerialportHandle* pSerialPort = new SerialportHandle;
//    connect(pSerialPort, &SerialportHandle::sig_recvMsg, this, &SerialportCtrl::sig_recvSerialMsg);
    connect(pSerialPort, &SerialportHandle::sig_recvMsg, this, &SerialportCtrl::onRecvDataFromSerial);
    pSerialPort->setSerialInfo(info);
    m_mapSerialPort.insert(info.name, pSerialPort);
    return open_port(info.name);
}

// 是否打开
bool SerialportCtrl::isOpened(QString connName)
{
    if (m_mapSerialPort.contains(connName))
    {
        return m_mapSerialPort[connName]->isOpened();
    }
    else
    {
        return false;
    }
}

// 打开串口
bool SerialportCtrl::open_port(QString connName, bool bAsync)
{
    SERIALPORTCONFIG_INSTANCE->getSerialPortInfo(m_vecSerialInfo);

    PSeriaPortInfo serialInfo;
    bool isExist = false;

    foreach (PSeriaPortInfo info , m_vecSerialInfo)
    {
        if (connName == info.name)
        {
            serialInfo = info;
            isExist = true;
            break;
        }
    }
    if (!isExist)
    {
        qWarning() << QStringLiteral("串口配置中不存在[%1]对象，无法重连").arg(connName);
        return false;
    }

    bool ret = false;

    if (!m_mapSerialPort.contains(connName))
    {
        ret = init_open_serial(serialInfo);
        return false;
    }

    m_mapSerialPort[connName]->setSerialInfo(serialInfo);

    if (bAsync)
    {
        QMetaObject::invokeMethod(m_mapSerialPort[connName], "onOpenPort", Qt::QueuedConnection,
             Q_ARG(QString, connName));
    }
    else
    {
        QMetaObject::invokeMethod(m_mapSerialPort[connName], "onOpenPort", Qt::BlockingQueuedConnection,
            Q_RETURN_ARG(bool, ret), Q_ARG(QString, connName));
    }

    return ret;
}

// 关闭串口
void SerialportCtrl::close_port(QString connName)
{
    QMetaObject::invokeMethod(m_mapSerialPort[connName], "onClosePort", Qt::QueuedConnection, Q_ARG(QString, connName));
}

// 发送数据
bool SerialportCtrl::write_data(QString connName, QString strSend, bool isHex, int msTimeOut, bool bAsync)
{
    bool ret = true;
    if (bAsync)
    {
        QMetaObject::invokeMethod(m_mapSerialPort[connName], "onWriteData", Qt::QueuedConnection,
            Q_ARG(QString, connName),
            Q_ARG(QString, strSend),
            Q_ARG(bool, isHex),
            Q_ARG(int, msTimeOut),
            Q_ARG(bool, bAsync));

    }else
    {
        QMetaObject::invokeMethod(m_mapSerialPort[connName], "onWriteData", Qt::BlockingQueuedConnection,
            Q_RETURN_ARG(bool, ret),
            Q_ARG(QString, connName),
            Q_ARG(QString, strSend),
            Q_ARG(bool, isHex),
            Q_ARG(int, msTimeOut),
            Q_ARG(bool, bAsync));
    }
    return ret;
}

// 读取数据
bool SerialportCtrl::read_data(QString connName, QString& strRecv,int msTimeOut)
{
    bool ret = false;
    QMetaObject::invokeMethod(m_mapSerialPort[connName], "onReadData", Qt::BlockingQueuedConnection,
        Q_RETURN_ARG(bool, ret),
        Q_ARG(QString, connName),
        Q_ARG(QString&, strRecv),
        Q_ARG(int, msTimeOut));

    return ret;
}

// 发送读取数据
bool SerialportCtrl::write_read_data(QString connName, QString strSend, QString& strRecv, bool isHex, int msTimeOut)
{
    bool ret = false;

    QMetaObject::invokeMethod(m_mapSerialPort[connName], "onWriteReadData", Qt::BlockingQueuedConnection,
        Q_RETURN_ARG(bool, ret),
        Q_ARG(QString, connName),
        Q_ARG(QString, strSend),
        Q_ARG(QString&, strRecv),
        Q_ARG(bool, isHex),
        Q_ARG(int, msTimeOut));

    return ret;
}

// 写入是否16进制
void SerialportCtrl::setRecvHexData(QString connName, bool bHexData)
{
    m_mapSerialPort[connName]->setRecvHexData(bHexData);
}

// 相应关闭槽
void SerialportCtrl::exitWork()
{
    QMap<QString, SerialportHandle*>::const_iterator iter;
    for (iter = m_mapSerialPort.constBegin(); iter != m_mapSerialPort.constEnd(); iter++)
    {
        close_port(iter.key());
    }
}

// 接收数据相应
void SerialportCtrl::onRecvDataFromSerial(QString name, QByteArray msg)
{
    // 获取当前时间
    QDateTime dataTime = QDateTime::currentDateTime();

    // 获取端口号
    SERIALPORTCONFIG_INSTANCE->getSerialPortInfo(m_vecSerialInfo);
    QString comNO;
    for (int i = 0; i < m_vecSerialInfo.size(); i++)
    {
        PSeriaPortInfo info = m_vecSerialInfo[i];
        if(name == info.name){
            comNO = info.comNO;
            break;
        }
    }
    // 显示接收信息
    QString strTime = dataTime.toString("HH:mm:ss");
    QString recv = QString("[%1]:%2 Recv:%3").arg(strTime).arg(comNO).arg(QString::fromLocal8Bit(msg));
    qDebug()<<recv;

    // 获取系统参数
    PSysparamInfo sys_info;
    SERIALPORTCONFIG_INSTANCE->getSysParamInfo(sys_info);

    // 获取页面参数
    PSettingInfo setting_info;
    SERIALPORTCONFIG_INSTANCE->getSettingInfo(setting_info);

    // 插入数据接收数据库
    QHash<QString,QVariant> insert_data;
    insert_data["dataNo"] = comNO;
    insert_data["dataContent"] = QString::fromLocal8Bit(msg);
    insert_data["dataTime"] = dataTime;
    mydb.db->addData("ysc_serialport",insert_data);

    // 处理接收值
    QString message = (QString)msg;
    QStringList list = message.split(" ");

    // 编号
    QString codeBoxEdit;
    // 发送报文
    QString sendEdit;

    // 获取当前毫秒数
    QString mesc = SERIALPORTCONFIG_INSTANCE->getMilliseconds(dataTime);
    // 整合报文
    QString strRecv;

    // 对数据来源进行判断
    if(name == "10001"){
        // 疲劳驾驶
        // 获取疲劳驾驶参数
        PSfatigueInfo serInfo;
        serInfo = setting_info.m_psfatigueInfo;

        QString m7 = list.at(7);
        QString m8 = list.at(8);
        QString mm = QString("%1%2").arg(m7).arg(m8);
        // 判断报警类型
        if(m7 == "51"){// 疲劳报警
            if(m8 == "01"){
                codeBoxEdit = "11";
                sendEdit = "打瞌睡";
            }else if(m8 == "02"){
                codeBoxEdit = "12";
                sendEdit = "分神驾驶";
            }else if(m8 == "03"){
                codeBoxEdit = "13";
                sendEdit = "拨打电话";
            }
        }else if(m7 == "52"){// 左顾右盼报警
            codeBoxEdit = "14";
            sendEdit = "抽烟";
        }else if(m7 == "53"){// 无人像报警
            codeBoxEdit = "15";
            sendEdit = "离岗";
        }
        if(!serInfo.warnType.contains(mm)){
            return;
        }
        // 根据报文编号查询上次发送数据
        int seconds;
        QList<QHash<QString,QString>> datas;
        QString sqlWhere = QString("where dataKind = 1 and dataType = 0 and dataNo = %1 order by dataTime desc limit 1 ").arg(codeBoxEdit);
        bool ret = mydb.db->getData("ysc_compass",datas,sqlWhere);
        if(ret){
            if(!datas.isEmpty()){
                QHash<QString,QString> childData = datas[0];
                QString time = childData.value("dataTime");
                // 计算时间差
                QDateTime time1 = QDateTime::fromString(time, "yyyy-MM-dd HH:mm:ss");
                seconds = time1.secsTo(dataTime);
            }else{
                seconds = -1;
            }

        }else{
            seconds = -1;
        }
        // 判断是否超时
        if(m7 == "51"){// 疲劳报警
            if(seconds >= serInfo.fatigue){
                seconds = -1;
            }
        }else if(m7 == "52"){// 左顾右盼报警
            if(seconds >= serInfo.gaze_round){
                seconds = -1;
            }
        }else if(m7 == "53"){// 无人像报警
            if(seconds >= serInfo.no_portrait){
                seconds = -1;
            }
        }else{
            seconds = -1;
        }
        // 判断是否需要发送报文
        if(seconds == -1){
            // 整合报文
            strRecv = QString("%1 %2 %3 %4").arg(codeBoxEdit)
                    .arg(mesc).arg(sendEdit).arg(sys_info.cplate);
            // 给指挥车发送报文
            m_udpTx.send(sys_info.sremote_udp_ip,sys_info.sudp_port,strRecv.toLocal8Bit());
            // 给运输车发送报文
            m_udpTx.send(sys_info.slocal_udp_ip,sys_info.sudp_port,strRecv.toLocal8Bit());

            // 插入北斗报文数据库
            QHash<QString,QVariant> insert_cdata;
            insert_cdata["dataKind"] = 1;
            insert_cdata["dataType"] = 0;
            insert_cdata["sender"] = sys_info.slocal_udp_ip;
            insert_cdata["receiver"] = sys_info.sremote_udp_ip;
            insert_cdata["dataNo"] = codeBoxEdit;
            insert_cdata["content"] = strRecv;
            insert_cdata["dataTime"] = dataTime;
            mydb.db->addData("ysc_compass",insert_cdata);
        }

    }else if(name == "10002"){
        // 车辆状态
        // 获取车辆状态参数
        PSvehicleInfo serInfo;
        serInfo = setting_info.m_psvehicleInfo;

        // 处理是否需要发送报文




        strRecv = QString("%1 %2 %3 %4").arg(codeBoxEdit)
                .arg(mesc).arg(sendEdit).arg(sys_info.cplate);
        // 给指挥车发送报文
        m_udpTx.send(sys_info.sremote_udp_ip,sys_info.sudp_port,strRecv.toLocal8Bit());
        // 给运输车发送报文
        m_udpTx.send(sys_info.slocal_udp_ip,sys_info.sudp_port,strRecv.toLocal8Bit());

        // 插入北斗报文数据库
        QHash<QString,QVariant> insert_cdata;
        insert_cdata["dataKind"] = 2;
        insert_cdata["dataType"] = 0;
        insert_cdata["sender"] = sys_info.slocal_udp_ip;
        insert_cdata["receiver"] = sys_info.sremote_udp_ip;
        insert_cdata["dataNo"] = codeBoxEdit;
        insert_cdata["content"] = strRecv;
        insert_cdata["dataTime"] = dataTime;
        mydb.db->addData("ysc_compass",insert_cdata);

    }else if(name == "10003"){
        // 货物位移
        // 获取货物位移参数
        PSdriftInfo serInfo;
        serInfo = setting_info.m_psdriftInfo;

        // 判断是否需要报警





        strRecv = QString("%1 %2 %3 %4").arg(codeBoxEdit)
                .arg(mesc).arg(sendEdit).arg(sys_info.cplate);
        // 给指挥车发送报文
        m_udpTx.send(sys_info.sremote_udp_ip,sys_info.sudp_port,strRecv.toLocal8Bit());

        // 插入北斗报文数据库
        QHash<QString,QVariant> insert_cdata;
        insert_cdata["dataKind"] = 2;
        insert_cdata["dataType"] = 0;
        insert_cdata["sender"] = sys_info.slocal_udp_ip;
        insert_cdata["receiver"] = sys_info.sremote_udp_ip;
        insert_cdata["dataNo"] = codeBoxEdit;
        insert_cdata["content"] = strRecv;
        insert_cdata["dataTime"] = dataTime;
        mydb.db->addData("ysc_compass",insert_cdata);
    }else if(name == "10004"){
        // 北斗接收
        codeBoxEdit = "11";
        sendEdit = "打瞌睡";


        strRecv = QString("%1 %2 %3 %4").arg(codeBoxEdit)
                .arg(mesc).arg(sendEdit).arg(sys_info.cplate);
        // 给运输车发送报文
        m_udpTx.send(sys_info.slocal_udp_ip,sys_info.sudp_port,strRecv.toLocal8Bit());

        // 插入北斗报文数据库
        QHash<QString,QVariant> insert_cdata;
        insert_cdata["dataKind"] = 0;
        insert_cdata["dataType"] = 1;
        insert_cdata["receiver"] = sys_info.slocal_udp_ip;
        insert_cdata["dataNo"] = codeBoxEdit;
        insert_cdata["content"] = strRecv;
        insert_cdata["dataTime"] = dataTime;
        mydb.db->addData("ysc_compass",insert_cdata);
    }
}

// 连接数据库
void SerialportCtrl::openDbConnect()
{
    //打开数据库
    auto ret = mydb.db->reOpenSql();
    if(!ret){
        qCritical("打开数据库失败");
    }else{
        qCritical("打开数据库成功");
    }
}
